Open Database Connectivity (ODBC) is a standard developed by Microsoft to simplify the development of applications that may have to target a variety of Database platforms. ODBC is implemented through a collection of database drivers that are provided by
Microsoft and third-party database vendors. ODBC database drivers provide your application with the capability to utilize a variety of database formats through the use of driver libraries. When using ODBC databases, it is possible to support more than one
database format using the same application source code. In order to switch databases, you would only need to switch ODBC drivers.
All ODBC-type databases are SQL-based. The developers of the ODBC drivers decide to which level of the ODBC specification the driver will be compliant. For a driver to be compliant, it must support all aspects of that level. There are three levels of
ODBC driver compliance:
The ODBC driver developer generally provides information regarding the level of compatibility of the drivers, as well as functions, methods, and data types that are supported. It also is possible for your application to determine the level of
conformance by using the following ODBC API calls (all ODBC API calls are located in the ODBC.DLL library included with Visual Basic):
Using ODBC, it is possible to have one application that can host a variety of database platforms using the same application code. This is accomplished through the use of ODBC database drivers that support the target database. With ODBC, it is possible
to create an application based on one ODBC-based database engine. After that application has been completed, you then can substitute an alternative ODBC-based database engine and your application will perform all its operations against the new ODBC-based
database engine.
The primary benefit of ODBC is that it enables your application to be database independent. To achieve the maximum benefit from ODBC, you must decide early in the design stage whether this is the route you want to follow. You must follow certain rules
to fully exploit the ODBC layer.
ODBC allows the developer to create an application using a locally available ODBC-compliant database (Oracle, for example). After the application is completed, the process to move the application to another ODBC database (an SQL server, for example) is
as simple as changing the ODBC connect string in the OpenDataBase function.
Listings 29.1 through 29.3 provide examples in order to illustrate the different methods available for opening an ODBC-type database. The methods illustrated here utilize the different parameters that can be used in conjunction with the OpenDatabase
method of a Workspace object for ODBC databases.
Dim db As DataBase Dim ws As WorkSpace Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") Set db = ws.OpenDatabase("", False, False, "ODBC;")
This example prompts the user to select from a list of previously defined ODBC data sources. The user will be prompted as the final step in opening the database. After the user selects a database, the database opens using the security information
provided in the CreateWorkspace statement. If the user chooses the Cancel option, a trappable error is generated.
Figure 29.1. The ODBC selection dialog box.
Dim db As Database Dim ws As Workspace Dim sconnect As String Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase=BIBLIO;UID=ADMIN;PWD=ADMIN" Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect)
Listing 29.2 opens the BIBLIO database and associates it to the data source type ORACLE. The user ID, ADMIN, and an empty password field are displayed. The user will have to enter a valid password prior to the database being opened. If the database
cannot be opened, a trappable error is generated.
Dim db As Database Dim ws As Workspace Dim sconnect As String Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase=BIBLIO;UID=;PWD=" Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect)
Listing 29.3 opens the BIBLIO database and associates it to the data source type ORACLE. Because the User ID and the password items have been omitted, a database Logon dialog box is displayed (see Figure 29.2). If the user chooses the Cancel option, a
trappable error is generated. If the database cannot be opened, a trappable error is generated.
Figure 29.2. The database Logon dialog box.
Utilizing the Data control or Data Access objects, you are able to manipulate an ODBC data source in the same manner as that of native Microsoft Access databases.
Before you can access an ODBC database, you first must set up the database using the ODBC application shipped as part of Visual Basic. You can find this application in the Windows Control Panel or in the Visual Basic program group.
To set up an ODBC source, perform the following steps (this example assumes that the ORACLE Version 7.1 ODBC driver has been installed on your system, but these steps would apply to all ODBC drivers):
Figure 29.3. The ODBC Oracle Setup dialog box.
The properties, methods, and events of the Data control have been fully described in Chapter 27, "The Data Control." The following section will deal only with the properties, methods, and events that are specific to the use of the Data control
with ODBC types of databases.
When connecting to an ODBC database, you must specify ODBC in the Connect property, and perhaps supply additional information such as user ID and password, as well as any additional information necessary dependent on the type of ODBC database you are
using. Further information on the Connect string for ODBC databases is supplied in the ODBC database driver documentation.
To set the Connect property at design time, enter the Connect string using the Property Editor.
To set the Connect property at runtime, use the following expression:
data1.connect= "OBDC;Database= BIBLIO;UID=ADMIN;PWD=ADMIN"
If you are using an ODBC type of database, this property must be left blank.
To set this property at design time, clear any entry contained in the DatabaseName property.
To set this property at runtime, use the following expression:
data1.DatabaseName=""
When using an ODBC database, you can set the Data control so that all SQL statements will be executed on the database server and not interpreted by the Jet Engine (the default Database engine supplied with Visual Basic). You would need to use the
Options setting in the following situations:
To set the Options property at design time, enter the dbSQLPassThrough constant into the Options property using the Property Editor.
To set this property at runtime, use this expression:
data1.options= dbSQLPassThrough
This section provides an example of opening an ORACLE database that is a copy of the BIBLIO database. This example is based on the bound controls example discussed in Chapter 27.
Control |
Name |
Caption |
Top |
Left |
Width |
Height |
FORM |
Form1 |
Bound Form |
1515 |
1920 |
6810 |
5190 |
Data |
Data1 |
Data control |
3360 |
0 |
6495 |
300 |
Label |
lblPubid |
Pub ID. |
180 |
180 |
1215 |
285 |
Label |
lblYear |
Year Pub. |
180 |
3660 |
1215 |
285 |
Label |
lblIsbn |
ISBN |
600 |
180 |
1215 |
285 |
Label |
lblTitle |
Title |
1020 |
180 |
1215 |
285 |
Label |
lblSubject |
Subject |
1440 |
180 |
1215 |
285 |
Label |
lblDescription |
Description |
1860 |
180 |
1215 |
285 |
Label |
lblComments |
Comments |
2280 |
180 |
1215 |
285 |
Label |
lblNotes |
Notes |
2700 |
180 |
1215 |
285 |
TextBox |
txtPubid |
|
180 |
1560 |
855 |
285 |
TextBox |
txtYear |
|
180 |
5040 |
855 |
285 |
TextBox |
txtIsbn |
|
600 |
1560 |
1635 |
285 |
TextBox |
txtTitle |
|
1020 |
1560 |
4635 |
285 |
TextBox |
txtSubject |
|
1440 |
1560 |
4635 |
285 |
TextBox |
txtDescription |
|
1860 |
1560 |
4635 |
285 |
TextBox |
txtComments |
|
2280 |
1560 |
4635 |
285 |
TextBox |
txtNotes |
|
2700 |
1560 |
4635 |
285 |
Command |
cmdExit |
E&xit |
4080 |
5400 |
795 |
295 |
TextBox txtPubid DataSource = data1 DataField = Pubid TextBox txtYear DataSource = data1 DataField = Year Published TextBox txtIsbn DataSource = data1 DataField = Isbn TextBox txtTitle DataSource = data1 DataField = Title TextBox txtSubject DataSource = data1 DataField = Subject TextBox txtDescription DataSource = data1 DataField = Description TextBox txtComments DataSource = data1 DataField = Comments TextBox txtNotes DataSource = data1 DataField = Notes
A window like the one shown in Figure 29.4 appears. Using the Data control's record navigation buttons, it is possible to move through all of the records contained in the title's recordset. Additionally, you can make changes to the contents of the
recordset by altering the information contained in the text boxes and using the Data control to change the current record.
Figure 29.4. Output from the bound Oracle database.
As you can see, you were able to switch the database that this application was using to another database with only changes being made to the Connect, DatabaseName, and the RecordSource properties.
You can use Data Access Objects (DAOs) to manipulate an ODBC database in the same manner as that of Microsoft Access databases. Primarily, this section will cover aspects of the DAO that are of particular importance when dealing with ODBC types of
databases. For a detailed look at the other facilities available in the Data Access Object, please refer to Chapter 28, "The Access Jet Engine."
The following properties of the DAO are to be used in conjunction with ODBC types of databases. Many of the properties examined here are to be used only with ODBC types of databases, hence they were only briefly covered in Chapter 28.
The CacheSize property of the Recordset object defines the number of records in the record set that should be stored in a local cache. The CacheSize property is not available on table or Snapshot types of recordsets.
The CacheStart property of the Recordset object defines the first cacheable record in the record set. This property is not available on table or Snapshot types of recordsets.
When opening a QueryDef (stored procedure) that is contained in an ODBC database, you need to specify ODBC in the Connect string, and perhaps supply additional information such as user ID and password. The additional information that needs to be
specified depends on the type of ODBC database. The additional information that must be supplied in the Connect string for the ODBC database is supplied in the ODBC database driver documentation.
The ExecuteSQL method of the database object is used only with ODBC-type databases. This method is provided for compatibility with earlier versions of Visual Basic. The ExecuteSQL method returns the number of rows affected. The SQL contained in the
ExecuteSQL method must be a nonrecord-returning SQL statement.
The Execute method has the SQLStatement parameter, which is a nonrecord-returning SQL statement.
Listing 29.5 illustrates the use of the ExecuteSQL method.
Dim db As Database Dim ws As Workspace Dim sconnect As String Dim rs As Recordset Dim nrows As Long Dim csql As String ' Now open the DataBase Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase= BIBLIO,UID=ADMIN,PWD=Admin" fSet db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect) Set rs = db.OpenRecordset("select * from titles", dbOpenDynaset, dbSQLPassThrough) csql = " update titles set notes = 'Test Notes' " nrows = db.ExecuteSQL(csql)
If this code were run against an ODBC-based database, the number of modified records would be contained in the nrows field.
The FillCache property of the Recordset object fills the previously allocated cache of the recordset with records from the database. When using the FillCache property, you must specify the number of records to retrieve, as well as the record number at
which the retrieval is to begin. The FillCache property is not available on table or Snapshot types of record sets.
Listing 29.6 illustrates the use of the CacheSize and CacheStart properties and the FillCache method of a recordset created from an ODBC data source. The FillCache method will fill the cache with 25 records, starting with record 25 in the rs recordset.
Dim db As Database Dim ws As Workspace Dim sconnect As String Dim rs As Recordset Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") ' Now open the DataBase Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect) Set rs = db.OpenRecordset("select * from titles", dbOpenDynaset, dbSQLPassThrough) rs.CacheSize = 25 rs.CacheStart = rs.Bookmark rs.FillCache rs.CacheSize, rs.CacheStart
The LoginTimeout property of the DBEngine object instructs the Jet Engine how long it should wait for a response to a Login request from an ODBC database. The LoginTimeout property defaults to 20 seconds. If you want your application to wait an
indefinite period of time, set the value to 0.
You use the LogMessages property to indicate whether the messages received during execution of a QueryDef against an ODBC database should be logged. The LogMessages property must be added to the QueryDef object using the CreateProperty method. All the
logged messages are stored in an ADMIN-xx table.
Listing 29.7 illustrates the use of the LogMessages property method.
Dim ws As Workspace Dim db As Database Dim qrynew As QueryDef Dim rstitles As Recordset Dim propmessages As Property Dim sconnect As String Set ws = DBEngine.CreateWorkspace("title", "Admin", "") Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect) ' Create a New QueryDef Set qrynew = db.CreateQueryDef("new", "Select * from titles where pubid = 13") ' Set the connect information for the Query sconnect = "DataBase= BIBLIO,UID=ADMIN,PWD=Admin" qrynew.Connect = sconnect ' Load The Recordset based on the New Query Set rstitles = db.OpenRecordset("new", dbOpenDynaset) Set propmessages = qrynew.CreateProperty("logmessages", dbBoolean, True, False) ' Save the Property definition qrynew.Properties.Append propmessages ' Set the Query to Log messages qrynew.logmessages = True
The ODBCTimeout property of the QueryDef object indicates the length of time the Jet Engine waits for a reply from an ODBC database before returning a time-out error to your application. The default value for the QueryTimeOut property is 60 seconds. To
force the QueryDef not to time-out, set the property to 0. The value of the ODBCTimeout overrides the value set for the QueryTimeOut property of the database object.
The OpenDataBase method or the WorkSpace object creates a connection between your application and the ODBC database and assigns it to a database type object. The OpenDataBase method contains the following parameters:
Listing 29.8 illustrates the opening of a registered Oracle database. If the database is not registered, a trappable error is generated.
Dim db As Database Dim ws As Workspace Dim sconnect As String Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase=BIBLIO;UID=ADMIN;PWD=" Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect)
The Option parameter of the OpenRecordset, CreateDynaset, CreateSnapshot, OpenTable, and Execute methods of the DataBase, QueryDef, and Recordset objects must be set to dbSQLPassThrough if you want the SQL statements associated with the creation of the
object to be processed on the database server and not be interpreted by the Jet Engine. This option is needed in the following situations:
Listing 29.9 shows how to use the dbSQLPassThrough option when creating a record set from an ODBC data source. This causes the SQL statement to be passed on to the database server for processing.
Dim db As Database Dim ws As Workspace Dim sconnect As String Dim rs As Recordset ' Now open the DataBase Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase= BIBLIO,UID=ADMIN,PWD=Admin" Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect) Set rs = db.OpenRecordset("select * from titles", dbOpenDynaset, dbSQLPassThrough)
You use the QueryTimeout property or the DataBase object to set the amount of time the DataBase object waits for a response to a query issued by the execute or ExecuteSQL method of the DataBase object. The value of the QueryTimeout property applies to
all SQL (such as ExecuteSQL) requests made to the ODBC data source. The QueryTimeout property defaults to 60 seconds.
The RegisterDataBase method of the DBEngine records information associated with the data source. This information includes the name of the data source, the type of data source, and the driver library that will be used to access the data source. This
information is then stored in the ODBC.INI file. The driver for the ODBC source reads this information and uses it to open the connection to the data source. Because the data source needs to be registered only once, it is perhaps a better idea to use the
ODBC function located in the Windows Control Panel to register your database, or to include the registration as part of your application setup.
The RegisterDataBase method has four parts to it:
Listing 29.10 illustrates the steps necessary to register the BIBLIO data source of the type of ORACLE.
Dim db As Database Dim ws As Workspace Dim sconnect As String sconnect = "network1" DBEngine.RegisterDatabase "BIBLIO", "ORACLE", True, sconnect ' Now open the Database Set ws = DBEngine.CreateWorkspace("ws1", "ADMIN", "") sconnect = "DataBase= BIBLIO,UID=ADMIN,PWD=Admin" Set db = ws.OpenDatabase("BIBLIO", False, False, "ODBC;" & sconnect)
The following methods of the Data Access Object DBEngine cannot be used with an ODBC type of database:
You are also unable to use the following database object creation methods, as each database handles the creation of its objects in a different manner:
As mentioned earlier, the supplier of your database software will include separate tools that will enable you to perform these functions.
Using the API effectively bypasses all Jet Engine interaction with the ODBC database. When using the ODBC API, you cannot use the native Visual Basic Data control or any of the bound control features of Visual Basic.
All the functions contained in the ODBC API are contained in the ODBC.DLL library.
Using the ODBC API is beyond the scope of this book, but I will touch briefly on some of the most important functions contained in the ODBC API. The majority of the calls outlined here are provided in the core level of compliance. You can find more
detailed information in the Microsoft ODBC SDK Guide. Where possible, the Visual Basic equivalents are listed:
When using the ODBC API, there are certain steps that must be performed each time that a session is to be established with the database server. The following functions are necessary to perform the steps:
Listing 29.11 illustrates the use of the preceding ODBC API functions in order to establish a session and open a database.
Sub OpenOdbcSource() Dim nenv As Long Dim nok As Integer Dim cdatasource As String Dim suserid As String Dim spassword As String nok = SQLAllocEnv(nenv) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured During the Allocation of the ODBC Environment" Exit Sub End If nok = SQLAllocConnect(nenv, nconnect) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured During the Allocation of ODBC Connections" Exit Sub End If ' change the following 3 lines for your environment cdatasource = "BIBLIO" suserid = "ADMIN" spassword = "PASSWORD" nok = SQLConnect(nconnect, cdatasource, Len(cdatasource), suserid, Len(suserid), spassword, Len(spassword)) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured During the Conection to the ODBC Database" Exit Sub End If MsgBox " You have sucessfully connected to the ODBC Database" End Sub
After you have opened the ODBC database, you can manipulate the data contained in the database. The following functions are necessary to select all of the records from a table (in this example, it is a table named Currencies):
Listing 29.12 illustrates the statements that are needed in addition to those in Listing 29.11 to create a recordset from the currency table stored in this ODBC database.
Dim nsql As Long Dim csql As String nok = SQLAllocStmt(nconnect, nsql) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured Allocating the SQL Results Handle" Exit Sub End If csql = " Select * from currency" nok = SQLExecDirect(nsql, csql, Len(csql)) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured Excuting the SQL Statment" Exit Sub End If MsgBox "SQL Completed Sucessfully " SQLNumResultsCol
After you have created an ODBC recordset, you can extract data from the table in order to place the information either into controls on a form or into variables that will be used later in your application. The following are the calls that are necessary
to read the data from the fields contained in the recordset.
Listing 29.13 illustrates the statements that are necessary in addition to those in Listings 29.11 and 29.12 to retrieve the value of a field from a recordset and to display it in a message box.
Dim cdata As String Dim nlong As Long Const SQL_C_CHAR = 1 nok = SQLFetch(nsql) If nok <> SQL_SUCCESS Then MsgBox "An Error Occured Obtaining the SQL Result Set" Exit Sub End If nok = SQLGetData(nsql, 1, SQL_C_CHAR, cdata, 30, nlong) If nok <> SQL_SUCCESS Then processerror nenv, nconnect, 0 MsgBox "An Error Occured Obtaining the Field Value" Exit Sub Else MsgBox "The Following data was retreived " * cdata End If
In the event of an error occurring during any of the ODBC API functions, the SQLError function will provide you with additional information in order to further diagnose the problem. In order to retrieve additional error information, you need to specify
the following information for the SQLError function:
The function will then return the following information:
The example contained in the opening and closing of an ODBC Data Source section illustrates the use of the SQLError function.
When closing an application that is using the ODBC API, you must manually close all of the connections that were opened when initiating the application. The functions and steps involved in closing the connections consist of the following:
The following example illustrates the opening and closing of an ODBC database using the ODBC API. Follow the steps listed here to create the example application(note that this is a 16-bit example):
When the project is running, you can connect the ODBC data source as defined in the cmdOdbcConnect_Click event. If an error occurs during the connect, you will receive a message box containing the complete text of the error. Once you have opened a
connection, you then can perform additional operations on the database using the examples presented earlier in this section. Press the Close button, and the connection to the database will be closed.
In this chapter, you looked at the features of ODBC as well as some of the benefits of ODBC. You learned to use a Data control to open an Oracle type database. You also explored the properties and methods of the Data control and the Data Access Objects that apply specifically to ODBC databases. Finally, you looked at a few of the ODBC API calls, their Visual Basic equivalents, as well as some examples illustrating the functionality of the ODBC API.